<template>
    <!--目前先这样，不开启还是el-table-->
    <vxe-table
        v-if="useVirtual"
        ref="table"
        :scroll-y="{
            gt: useVirtual ? 100 : -1
        }"
        :resizable="true"
        :auto-resize="true"
        :data="tableData"
        :stripe="config.stripe"
        show-header-overflow
        :highlightCurrentRow="config.highlightCurrentRow"
        :highlightHoverRow="config.highlightCurrentRow"
        height="100%"
        :row-height="29"
        :show-header="config.showHeader"
        :border="config.border"
        :show-footer="config.showSummary"
        :footer-method="footerMethod"
        size="mini"
        class="base-table mytable-scrollbar sortable"
        row-class-name="vxeRowStyle"
        header-row-class-name="base-table-header__row"
        cell-class-name="row"
        :style="{
            width: config.width
        }"
        :checkbox-config="{
            labelField: 'name',
            strict: true,
            checkMethod: checkMethod
        }"
        @cell-dblclick="
            (target) => {
                viewDetail(true, target);
            }
        "
        @cell-click="
            (target) => {
                rowClick(true, target);
            }
        "
        @checkbox-all="
            (target) => {
                select(true, target);
            }
        "
        @checkbox-change="
            (target) => {
                select(true, target);
            }
        "
    >
        <vxe-table-column v-if="config.isMultiSelect" type="checkbox" fixed="left" width="60" align="center" />
        <vxe-table-column v-if="config.isIndex" type="seq" fixed="left" width="60" align="center" :title="$t('reportCommonWord.index')" />
        <vxe-table-column
            v-for="(item, index) in permissionTableHeader"
            :key="item.value"
            :title="$t(item.lang) || item.label || item.lable"
            :field="item.value"
            :min-width="item.width || 60"
            filter-placement="bottom"
            :fixed="item.fixed"
            :filters="item.filters"
            :filter-method="filterNameMethod"
            :column-key="item.filterKey"
            :show-overflow="!item.tooltip"
            :class-name="item.filters ? '' : 'no-filters'"
            :align="item.align || 'left'"
        >
            <template slot="header">
                <!-- 这里要自行写方法 -->
                <slot name="headerCell" :scope="{ item, cell: item }">
                    <!-- 如果有必填 -->
                    <span v-if="item.required" class="pdl-10 color-red">*</span>
                    <span>{{ $t(item.lang) || item.label }}</span>
                </slot>
            </template>
            <template slot-scope="{ row, $rowIndex }">
                <slot name="tableCell" :scope="{ row, item, cell: item, index, $index: $rowIndex }">
                    <!-- <span class="pdl-10">{{ row[item.value] }}</span> -->
                    <span class="pdl-10" :class="[item.highRow ? 'highRow' : '']">{{
                        item.formatter ? item.formatter({ row, $index }) : row[item.value]
                    }}</span>
                </slot>
            </template>
        </vxe-table-column>
        <vxe-table-column
            v-if="config.isShowOpera"
            :title="$t('layout.btns.operation')"
            align="center"
            fixed="right"
            :width="config.operatWidth || '100px'"
        >
            <template slot-scope="scope">
                <slot :scope="{ ...scope, $index: scope.$rowIndex }">
                    <div class="btn-group">
                        <div v-if="!scope.row.edit">
                            <el-button
                                v-if="config.showEditBtn"
                                id="btn_t_blue"
                                type="text"
                                size="mini"
                                :disabled="disabled"
                                @click.stop.prevent="editItem(indexFormat(scope))"
                            >
                                {{ config.showDeleteBtn ? $t('layout.btns.edit') : $t('layout.btns.checkDetail') }}
                            </el-button>
                            <el-button
                                v-if="config.showDeleteBtn"
                                id="btn_t_red"
                                type="text"
                                size="mini"
                                :disabled="disabled"
                                @click.stop.prevent="deleteItem(scope)"
                            >
                                {{ $t('layout.btns.delete') }}
                            </el-button>
                        </div>
                        <div v-else>
                            <el-button
                                id="btn_t_blue"
                                type="text"
                                :disabled="disabled"
                                size="mini"
                                @click.stop.prevent="saveItem(indexFormat(scope))"
                            >
                                {{ $t('layout.btns.save') }}
                            </el-button>
                            <el-button
                                id="btn_t_gray"
                                type="text"
                                :disabled="disabled"
                                size="mini"
                                @click.stop.prevent="cancelItem(indexFormat(scope))"
                            >
                                {{ $t('layout.btns.cancel') }}
                            </el-button>
                        </div>
                    </div>
                </slot>
            </template>
        </vxe-table-column>
    </vxe-table>
    <el-table
        v-else
        ref="table"
        :data="tableData"
        :stripe="config.stripe"
        :highlightCurrentRow="config.highlightCurrentRow"
        :height="config.height"
        :max-height="config.maxHeight"
        :show-header="config.showHeader"
        :border="config.border"
        :show-summary="config.showSummary"
        :summary-method="getSummaries"
        :default-expand-all="config.defaultExpandAll"
        row-key="id"
        current-row-key="id"
        size="mini"
        class="base-table sortable"
        :row-class-name="getRowClass"
        header-row-class-name="base-table-header__row"
        cell-class-name="row"
        :style="{ width: config.width }"
        @row-dblclick="
            (target) => {
                viewDetail(false, target);
            }
        "
        @row-click="
            (target) => {
                rowClick(false, target);
            }
        "
        @select-all="
            (target) => {
                select(false, target);
            }
        "
        @select="
            (target) => {
                select(false, target);
            }
        "
        @filter-change="filterChange"
        @cell-mouse-enter="cellMove"
    >
        <el-table-column v-if="config.isMultiSelect" fixed="left" type="selection" :selectable="selectable" width="60" align="center" />
        <el-table-column v-if="config.isIndex" type="index" min-width="70" :label="$t('reportCommonWord.index')" align="left" class-name="pdl-10" />
        <el-table-column
            v-for="(item, index) in permissionTableHeader"
            :key="item.value + item.label"
            :show-overflow-tooltip="!item.tooltip"
            :label="$t(item.lang) || item.label || item.lable"
            :prop="item.value"
            :min-width="item.width"
            :width="item.fixWidth"
            filter-placement="bottom"
            :fixed="item.fixed"
            :filters="item.filters"
            :column-key="item.filterKey"
            :class-name="item.filters ? '' : 'no-filters'"
            :align="item.align || 'left'"
        >
            <!-- 二级表头 -->
            <template v-if="item.children && item.children.length">
                <el-table-column
                    v-for="children in item.children"
                    :key="children.value + children.label"
                    :show-overflow-tooltip="!children.tooltip"
                    :label="$t(children.lang) || children.label || children.lable"
                    :prop="children.value"
                    :min-width="children.width"
                    :width="children.fixWidth"
                    filter-placement="bottom"
                    :fixed="children.fixed"
                    :filters="children.filters"
                    :column-key="children.filterKey"
                    :class-name="children.filters ? '' : 'no-filters'"
                    :align="children.align || 'left'"
                >
                    <template slot="header">
                        <!-- 这里要自行写方法 -->
                        <slot name="headerCell" :scope="{ item: children, cell: children }">
                            <!-- 如果有必填 -->
                            <span v-if="children.require" class="pdl-10 color-red">*</span>
                            <span class="pdl-10">{{ $t(children.lang) || children.label }}</span>
                        </slot>
                    </template>
                    <template slot-scope="{ row, $index }">
                        <slot name="tableCell" :scope="{ row, item: children, cell: children, $index }">
                            <span class="pdl-10">{{ row[children.value] }}</span>
                        </slot>
                    </template>
                </el-table-column>
            </template>
            <template slot="header">
                <!-- 这里要自行写方法 -->
                <slot name="headerCell" :scope="{ item, cell: item, index }">
                    <!-- 如果有必填 -->
                    <span v-if="item.require" class="pdl-10 color-red">*</span>
                    <span class="pdl-10">{{ $t(item.lang) || item.label }}</span>
                </slot>
            </template>
            <template slot-scope="{ row, $index }">
                <slot name="tableCell" :scope="{ row, item, cell: item, index, $index }">
                    <!-- <span class="pdl-10">{{ row[item.value] }}</span> -->
                    <span class="pdl-10" :class="[item.highRow ? 'highRow' : '']">{{
                        item.formatter ? item.formatter({ row, $index }) : row[item.value]
                    }}</span>
                </slot>
            </template>
        </el-table-column>
        <el-table-column
            v-if="config.isShowOpera"
            :label="$t('layout.btns.operation')"
            align="center"
            fixed="right"
            :width="config.operatWidth || '100px'"
        >
            <template slot-scope="scope">
                <slot :scope="scope">
                    <div class="btn-group">
                        <div v-if="!scope.row.edit">
                            <el-button
                                v-if="config.showEditBtn"
                                id="btn_t_blue"
                                type="text"
                                size="mini"
                                :disabled="disabled"
                                @click.stop.prevent="editItem(scope)"
                            >
                                {{ config.showDeleteBtn ? $t('layout.btns.edit') : $t('layout.btns.checkDetail') }}
                            </el-button>
                            <el-button
                                v-if="config.showDeleteBtn"
                                id="btn_t_gray"
                                type="text"
                                size="mini"
                                :disabled="disabled"
                                @click.stop.prevent="deleteItem(scope)"
                            >
                                {{ $t('layout.btns.delete') }}
                            </el-button>
                        </div>
                        <div v-else>
                            <el-button id="btn_t_blue" type="text" :disabled="disabled" size="mini" @click.stop.prevent="saveItem(scope)">
                                {{ $t('layout.btns.save') }}
                            </el-button>
                            <el-button id="btn_t_gray" type="text" :disabled="disabled" size="mini" @click.stop.prevent="cancelItem(scope)">
                                {{ $t('layout.btns.cancel') }}
                            </el-button>
                        </div>
                    </div>
                </slot>
            </template>
        </el-table-column>
    </el-table>
</template>

<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';
import { Prop, Emit, Watch } from 'vue-property-decorator';
import { TableHeaderConfig, TabelConfig, Dictionary } from '@/typings';
import { PermissionConfig } from '@/store/modules/common-module';
import { Tools } from '@/utils/tools';
import libraryScript from '../../library';
import Sortable from 'sortablejs';
import XEUtils from 'xe-utils';
const DEFAULT_CONFIG: TabelConfig = {
    isMultiSelect: true,
    isShowOpera: true,
    fieldsArr: ['id'],
    maxHeight: '600px',
    sortable: false,
    border: true,
    isRight: 'right',
    width: '100%',
    stripe: false,
    isIndex: false,
    operatWidth: 100,
    showHeader: true,
    rowId: 'id',
    showSummary: false,
    highlightCurrentRow: true,
    id: 'id',
    defaultExpandAll: false,
    showEditBtn: true,
    showDeleteBtn: true
};

@Component({
    name: 'base-table'
})
export default class App extends Vue {
    @Prop({ default: false }) useVirtual: boolean;
    @Prop({ required: true }) tableData: any[];

    @Prop() tableConfig: TabelConfig;

    @Prop({ required: true }) colunmData: TableHeaderConfig[];

    @Prop({ default: false }) disabled: boolean;

    @Prop({
        default: function () {
            return {};
        }
    })
    totalColumn: Dictionary;

    @Watch('totalColumn')
    onTotalColumnChange(val) {
        if (this.useVirtual) {
            this.$nextTick(() => {
                this.updateFooter();
            });
        }
    }
    @Watch('tableData', { deep: true, immediate: true })
    onTableDataChange(val) {
        if (this.useVirtual && val.length) {
            Tools.debounce(this.updateFooter(), 2000);
        }
    }

    @Watch('tableConfig', { immediate: true, deep: true })
    onValueChanged(val: TabelConfig) {
        this.config = Object.assign({}, DEFAULT_CONFIG, val);
    }
    @Watch('tableConfig.sortable', { immediate: true, deep: true })
    onSortableChanged(val: TabelConfig) {
        // this.config = Object.assign({}, DEFAULT_CONFIG, val);
        if (val) {
            this.bindSort();
        } else {
            this.sortable = null;
        }
    }
    @Watch('colunmData', { immediate: true })
    onFormListChange(val: TableHeaderConfig[]) {
        const vuexStore = this.$store.state[this.$route.meta.moduleId];
        if (vuexStore && vuexStore.v_permission) {
            const permissionObj: PermissionConfig = vuexStore.v_permission;
            this.permissionTableHeader = this.getPermissinTableHeader(val, permissionObj);
        } else {
            this.permissionTableHeader = val;
        }
        // 如果没有启用内长 则去掉内长
        if (!this.isShowLong) {
            this.permissionTableHeader = this.permissionTableHeader.filter((item) => item.value !== 'longName');
        }
    }

    get isShowLong() {
        const falg = localStorage.getItem('Use_Long') === 'true';
        return falg;
    }

    // 需要汇总得字段
    config: TabelConfig = DEFAULT_CONFIG;
    permissionTableHeader: TableHeaderConfig[] = [];
    sortable: any = null;
    // methods
    // 绑定拖拽
    bindSort() {
        this.$nextTick(() => {
            setTimeout(() => {
                const ref: any = this.$refs.table;
                console.log('bindSort ref', ref);
                const el = ref && ref.$el.querySelectorAll('.sortable .el-table__body-wrapper tbody')[0];
                el && this.setSort(el);
            }, 2000);
        });
    }
    setSort(el) {
        // const els = this.$refs.table.$el.querySelectorAll('.el-table__body-wrapper > table > tbody')[0]
        this.sortable = Sortable.create(el, {
            ghostClass: 'sortable-ghost', // Class name for the drop placeholder,
            setData: function (dataTransfer) {
                // to avoid Firefox bug
                // Detail see : https://github.com/RubaXa/Sortable/issues/1012
                dataTransfer.setData('Text', '');
            },
            onEnd: (evt) => {
                const currRow = this.tableData.splice(evt.oldIndex, 1)[0];
                this.tableData.splice(evt.newIndex, 0, currRow);
                this.$nextTick(() => {
                    this.tableData.forEach((item, index) => {
                        item = Object.assign(item, {
                            index: index + 1
                            // areaOrderNumber: index + 1,
                            // orderNumber: index + 1
                        });
                    });
                });
                this.$emit('dragTable', {
                    newIndex: evt.newIndex,
                    oldIndex: evt.oldIndex
                });
            }
        });
    }
    // 更新汇总
    updateFooter() {
        const ref = this.$refs['table'] as any;
        ref && ref.updateFooter();
    }
    select(vxe, target) {
        const section = vxe ? target['selection'] : target;
        const formatSection = this.commonSelectMethods(section);
        this.$emit('select', { section, formatSection });
    }
    // 根据权限数据 过滤得到列表
    getPermissinTableHeader(tableHeader: TableHeaderConfig[], permissionObj: PermissionConfig) {
        return tableHeader.reduce((k: TableHeaderConfig[], m) => {
            // 如果有设置 permissionKey 没有的话 大驼峰写法转小驼峰
            const newKey = m.permissionKey ? m.permissionKey : Tools.toLowerCase(m.value);
            if (permissionObj.fields.field.includes(newKey)) {
                // 验证是否有编辑权限
                m.isEdit = !permissionObj.fields.edit.includes(newKey);
                // 如果没有浏览权限则隐藏掉
                if (permissionObj.fields.browse.includes(newKey)) k.push(m);
            } else {
                k.push(m);
            }
            return k;
        }, []);
    }
    @Emit('viewDetail')
    viewDetail(vxe, target) {
        return vxe ? target.row : target;
    }
    @Emit('rowClick')
    rowClick(vxe, target) {
        return vxe ? target.row : target;
    }

    editItem({ row, $index }) {
        this.$emit('editItem', { row, $index });
    }
    deleteItem({ row, $index }) {
        this.$emit('deleteItem', { row, $index });
    }
    saveItem({ row, $index }) {
        this.$emit('saveItem', { row, $index });
    }
    cancelItem({ row, $index }) {
        this.$emit('cancelItem', { row, $index });
    }
    filterNameMethod({ value, row, column }) {
        return XEUtils.toValueString(row.name).toLowerCase().indexOf(value) > -1;
    }
    // 表格的筛选数据
    filterHandler(value, row, column) {
        const property = column['columnKey'];
        return row[property].includes(value);
    }
    filterChange(filters) {
        this.$emit('filterChange', filters);
    }

    commonSelectMethods(table) {
        const fields = this.config.fieldsArr;
        if (!fields) return [];
        return fields.reduce((k: any[], m: string) => {
            for (const item of table) {
                k.push({ [m]: item[m] });
            }
            return k;
        }, []);
    }
    // 高亮当前行
    setHighLightRow(row) {
        this.$nextTick(() => {
            (this.$refs.table as any).setCurrentRow(row);
        });
    }
    // 设置某项已勾选
    setToggleRowSelection(row) {
        (this.$refs.table as any).toggleRowSelection(row, true);
    }

    selectable() {
        return !this.disabled;
    }
    checkMethod({ row }) {
        return this.disabled || !row.disabled;
    }
    cellMove() {
        this.$emit('cellMove');
    }
    sort(prop) {
        (this.$refs.table as any).sort(prop, 'ascending');
    }
    doLayout() {
        (this.$refs.table as any).doLayout();
    }
    // 滚动到具体行
    tableScroll(height: number) {
        const dom: any = this.$refs.table;
        this.$nextTick(() => {
            dom.bodyWrapper.scrollTop = height;
        });
    }
    // 滚动到最底部
    tableScrollBottom() {
        const dom: any = this.$refs.table;
        this.$nextTick(() => {
            dom.bodyWrapper.scrollTop = dom.bodyWrapper.scrollHeight;
        });
    }

    getRowClass({ row }) {
        if (row.class) {
            return row.class;
        }
    }
    getSummaries(param) {
        const { columns, data } = param;
        const sums = this.getTotal(columns, data);
        return sums;
    }

    indexFormat(scope) {
        const { $rowIndex } = scope;
        scope.$index = $rowIndex;
        delete scope.$rowIndex;
        return scope;
    }

    footerMethod(param) {
        const { columns, data } = param;
        const sums = this.getTotal(columns, data);
        return [sums];
    }
    getTotal(columns, data) {
        const sums: string[] = [];
        columns.forEach((column, index) => {
            if (index === 0) {
                sums[index] = '合计';
                return;
            }
            if (!column.property) return;
            // 不需要合计的行直接跳过
            if (!this.permissionTableHeader.find((item) => item.value === column.property)!.isShowTotal) {
                return;
            }
            // this.disabled 表示 处于浏览状态 用后端的数据
            if (this.disabled && Object.keys(this.totalColumn).length > 0) {
                // eslint-disable-next-line no-prototype-builtins
                if (this.totalColumn.hasOwnProperty(column.property)) {
                    sums[index] = this.totalColumn[column.property];
                }
            } else {
                const values = data.map((item) => Number(item[column.property]));
                if (!values.every((value) => isNaN(value))) {
                    sums[index] = values.reduce((prev, curr) => {
                        const value = Number(curr);
                        if (!isNaN(value)) {
                            // return Number((prev + curr).toFixed(2))
                            return Number(prev + curr);
                        } else {
                            return prev;
                        }
                    }, 0);
                }
            }
            // const values = data.map((item) => Number(item[column.property]))
            // if (!values.every((value) => isNaN(value))) {
            //   sums[index] = values.reduce((prev, curr) => {
            //     const value = Number(curr)
            //     if (!isNaN(value)) {
            //       // return Number((prev + curr).toFixed(2))
            //       return Number((prev + curr))
            //     } else {
            //       return prev
            //     }
            //   }, 0)
            // }
        });
        return sums;
    }

    async exportExcel(name) {
        // 加载导出脚本
        const scriptStatus: boolean[] = [];
        const printScript = libraryScript.excelExport;
        for (const file of printScript) {
            const res: boolean = await Tools.synchronizationLoad(file);
            scriptStatus.push(res);
        }
        if (scriptStatus.indexOf(false) === -1) {
            const XLSX = window['XLSX'];
            const xlsxParam = { raw: true };
            const dom = (this.$refs['table'] as any).$el;
            const wb = XLSX.utils.table_to_book(dom, xlsxParam);
            const wbout = XLSX.write(wb, {
                bookType: 'xlsx',
                bookSST: true,
                type: 'array'
            });
            try {
                const url = window.URL.createObjectURL(new Blob([wbout]));
                const link = document.createElement('a');
                link.style.display = 'none';
                link.href = url;
                link.download = `${name}.xlsx`;
                document.body.appendChild(link);
                link.click();
                URL.revokeObjectURL(link.href); // 释放URL 对象
                document.body.removeChild(link);
            } catch (e) {
                this.$message.error(`导出失败:${e}`);
            }
        }
    }
}
</script>

<style lang="scss">
@import 'src/styles/variables.scss';
.base-table {
    /deep/.is-left.pdl-10 {
        padding-left: 10px !important;
    }
    /deep/.no-filters .el-table__column-filter-trigger {
        display: none;
    }
    .caret-wrapper {
        height: $thHeight;
        .sort-caret {
            border-width: 4px;
        }
        .sort-caret.ascending {
            top: 5px;
        }
        .sort-caret.descending {
            bottom: 5px;
        }
    }
    .vxeRowStyle {
        padding: 0 !important;
        margin: 0 !important;
        height: 28px !important;
        td {
            height: 28px !important;
            line-height: normal !important;
            .vxe-cell {
                line-height: 28px !important;
                height: 28px !important;
                padding: 0 !important;
            }
        }
    }
    .vxe-table--footer-wrapper {
        /* margin-top: -10px !important;*/
        /*height: 28px !important;*/
        .vxe-footer--row {
            background: #ededed;
            height: 28px !important;
            td {
                line-height: normal;
            }
        }
    }
    th {
        padding: 0 !important;
        height: $thHeight !important;
    }
    .row {
        padding: 0 !important;
        height: $thHeight !important;
    }
    /deep/.el-table-column--selection {
        /deep/ .cell {
            padding: 0 !important;
        }
    }
    /deep/.el-table__footer-wrapper {
        /deep/ td {
            padding: 0 0 0 10px !important;
        }
        /deep/ .cell {
            padding: 0 !important;
        }
    }
}
.btn-group {
    display: inline-block;
}
.mytable-scrollbar div::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}
/*滚动条的轨道*/
.mytable-scrollbar div::-webkit-scrollbar-track {
    background-color: #ffffff;
}
/*滚动条里面的小方块，能向上向下移动*/
.mytable-scrollbar div::-webkit-scrollbar-thumb {
    background-color: #bfbfbf;
    border-radius: 5px;
    border: 1px solid #f1f1f1;
    box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
}
.mytable-scrollbar div::-webkit-scrollbar-thumb:hover {
    background-color: #a8a8a8;
}
.mytable-scrollbar div::-webkit-scrollbar-thumb:active {
    background-color: #787878;
}
/*边角，即两个滚动条的交汇处*/
.mytable-scrollbar div::-webkit-scrollbar-corner {
    background-color: #ffffff;
}
</style>
<style lang="scss" scoped>
.filter-btn {
    text-align: right;
    height: 32px;
    line-height: 32px;
    margin: 6px -12px -12px -12px;
    box-shadow: 0px 0px 6px 0px rgba(238, 238, 238, 1);
    padding: 0 12px;
}
</style>
